package com.pentajock.docdb.types;

import com.pentajock.docdb.database.DBController;
import com.pentajock.docdb.utils.Utils;
import java.io.File;
import java.util.Date;
//import java.util.Map;
import java.util.Set;
import java.net.URI;

public class Document implements Comparable<Document> {
	private int documentID;
	private String departmentName;
	private String documentName;
	private String extension;
	private String category;
	private Date effectiveDate;
	private java.sql.Date sqlDate;
	private int updateInterval;
	private String path;
	private String fullPath;
	private String activeXCall;
	private boolean isApproved;
	private String assignee;
	private String newDocumentName;
	private File docFile;
	private File asgFile;
	private File awtFile;
	private File arcFile;
	private File aprFile;
	
	private DocumentProperties properties;
	
	public Document(int documentID,
					String departmentName,
					String documentName,
					String extension,
					String category,
					Date effectiveDate,
					int updateInterval,
					String path,
					boolean isApproved,
					String newDocumentName, 
					String assignee,
					String activeXCall) {
		this.documentID = documentID;
		this.departmentName = departmentName;
		this.documentName = documentName;
		this.extension = extension;
		this.category = category;
		this.effectiveDate = effectiveDate;
		this.updateInterval = updateInterval;
		this.path = appendSlash(path);
		this.isApproved = isApproved;
		this.activeXCall = activeXCall;
		this.newDocumentName = newDocumentName;
		this.assignee = assignee;
		this.docFile = null;
		this.asgFile = null;
		this.awtFile = null;
		this.arcFile = null;
		this.aprFile = null;
		this.sqlDate = null;
		
		this.properties = new DocumentProperties();
	}
	
	public Object[][] getComponents() {
		return new Object[][] {
			{documentID,
				departmentName, 
				documentName, 
				extension, 
				category, 
				effectiveDate,
				updateInterval, 
				path, 
				isApproved, 
				newDocumentName, 
				assignee},
			{"Document ID",
				"Department",
				"Subject", 
				"Extension", 
				"Category", 
				"Effective Date",
				"Update Interval", 
				"Path", 
				"Is Approved", 
				"New Subject",
				"Assignee"}
			};
	}
	
	public String getProperty(Object o) {
		if (o instanceof String)
			return properties.getProperty((String)o);
		else
			return null;        
	}
	
	private String relativizePath(String rootPath, String docPath) {
		try {
			URI rootURI = new URI(rootPath);
			URI pathURI = new URI(docPath);
			return pathURI.relativize(rootURI).toString();
		}
		catch (Exception e) {
		}
		return path;
	}
	
	private String appendSlash(String s) {
		return (s == null || (s.endsWith("/") || s.endsWith("\\"))) ? s : s + "/";
	}
	
	public Date getEffectiveDate() {
		return effectiveDate;
	}
	
	/*
	 * This converts a java.util.Date to java.sql.Date, for adding a document
	 * to the database.
	 */
	public java.sql.Date getSqlDate() {
		if (sqlDate == null)
			sqlDate = new java.sql.Date(effectiveDate.getTime());
		return sqlDate;
	}
	
	public void setEffectiveDate(Date effectiveDate) {
		this.effectiveDate = effectiveDate;
	}
	
	public void setProperties(DocumentProperties properties) {
		this.properties = properties;
	}
	
	public DocumentProperties getProperties() {
		return properties;
	}

	public Set<String> getPropertyNames() {
		return properties.asMap().keySet();
	}

	public int getDocumentID() {
		return documentID;
	}
	
	public String getNewDocumentName() {
		return newDocumentName;
	}
	
	public String getDepartmentName() {
		return departmentName;
	}
	
	public void setDepartmentName(String departmentName) {
		if (departmentName == "" || departmentName.trim().equals(""))
			this.departmentName = "-1";
		else
			this.departmentName = departmentName;
	}
	
	public String getDocumentName() {
		return documentName;
	}
	
	public String getExtension() {
		return extension;
	}
	
	public String getCategory() {
		return category;
	}
	
	public void setCategory(String category) {
		this.category = category;
	}
	
	public int getUpdateInterval() {
		return updateInterval;
	}
	
	public void setUpdateInterval(int updateInterval) {
		this.updateInterval = updateInterval;
	}
	
	public String getPath() {
		return path;
	}
	
	/*
	 * Usefull for new database entries
	 */
	public String getRelativePath() {
		return relativizePath(Utils.getDocRoot(), path);
	}
	
	public boolean isApproved() {
		return isApproved;
	}
	
	public void setApproved(boolean isApproved) {
		this.isApproved = isApproved;
	}
	
	public String getActiveXCall() {
		return activeXCall;
	}
	
	/*
	 * Full path could point to two locations
	 * 1. A relative path against your document root
	 * 2. An abolute path to the file, such as a second drive, outside folder
	 * The easiest way for me to determine this is to see which location
	 * actually exists.  ** Note: There's a chance it will exist in both! :)
	 */
	public String getFullPath() {
		if (fullPath == null) {
			File relativeFile = new File(Utils.getDocRoot() + getPath() + getFullName());
			File absoluteFile = new File(getPath() + getFullName());
			fullPath = relativeFile.exists() ? relativeFile.getPath() : absoluteFile.getPath();
		}
		return fullPath;
	}
	
	public String getFullPath(User u) {
		return Utils.getDocRoot() + getPath() + getFullName(u);
	}
	
	public String getFullName() {
		return getDocumentName() + "." + getExtension();
	}
	
	/*
	 * Assumes owed/due listing
	 */
	public String getFullName(User u) {
		return (getNewDocumentName()==null?getDocumentName():getNewDocumentName()) + "." + getExtension();
	}

	public String getDocumentName(User u) {
		return (getNewDocumentName()==null?getDocumentName():getNewDocumentName());
	}

	public boolean equals(Object o) {
		if(o != null && o instanceof Document) {
			return getDocumentID() == ((Document)o).getDocumentID();
		}
		return false;
	}
	
	public int compareTo(Document doc) {
		return getDocumentName().compareTo(doc.getDocumentName());
	}
	
	public Object getAssignee(boolean returnUser) {
		if (returnUser)
			return DBController.getUser(assignee);
		return assignee;
	}
	
	public String getAssignee() {
		return (String)getAssignee(false);
	}
	
	public boolean setAssignee(Object o) {
		if (o == null)
			assignee = null;
		if (o instanceof User)
			assignee = ((User)o).getUserName();
		else if (o instanceof String)
			assignee = ((String)o);
		else
			return false;
		return true;
	}
	
	public String toString() {
		return getDocumentName();
	}
	
	/* 
	 * Returns the file from the approved folder
	 * ** Note: For newly created procedures, this is inevitably
	 * wrong since they aren't approved yet, so use one 
	 * of the below methods
	 */
	public File toFile() {
		if (docFile == null) {
			File f = new File(getFullPath());
			if (f.exists()) {
				docFile = f;
			}
			else {
				docFile = null;
			}
		}
		return docFile;
	}
	
	/* 
	 * Returns the file from the assigned folder (The user's "what do i owe")
	 * Assumes owed/due listing
	 */
	public File toAssignedFile(User u) {
		if (asgFile == null)
			asgFile = new File(Utils.getUserRoot(u) + getFullName(u));
		return asgFile;
	}
	
	/*
	 * Returns the file from the awaiting approval folder
	 * Assumes awaiting/done listing
	 */
	public File toAwaitingFile(User u) {
		if (awtFile == null)
			awtFile = new File(Utils.getDoneRoot(u) + getFullName(u));
		return awtFile;
	}
	
	/*
	 * Returns the archived path for this file 
	 * (unlike the above two, this probably doesn't exist yet)
	 */ 
	public File toArchivedFile() {
		if (arcFile == null)
			arcFile = new File(Utils.getArchiveRoot() + getPath() + getFullName());
		return arcFile;
	}
	
	/*
	 * Returns the approved file path, but
	 * compensates for name changes
	 */
	 public File toApprovedFile(User u) {
		 if (aprFile == null)
			 aprFile = new File(getFullPath(u));
		 return aprFile;
	 }
}
